package com.palfund.butterknife.reflect;

import com.palfund.butterknifedemo.annotation.TestAnnotation;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * Created by clvc on 2017/8/21.
 * 真正的速度是看不见的 !
 * Today is today , we will go !
 */

public class ReflectDemo {
    @TestAnnotation(value = "test", count = 3, chars = 'W')
    public void test() {
        ReflectDemo reflectDemo = new ReflectDemo();
        Class<ReflectDemo> reflectClass = ReflectDemo.class;
        // 获取该类的存放路径(包路径)
        Package aPackage = reflectClass.getPackage();
        // 获取该类的名称
        String name = reflectClass.getName();
        // 获取该类继承的类
        Class<? super ReflectDemo> superclass = reflectClass.getSuperclass();
        // 获取该类实现的接口
        Class<?>[] interfaces = reflectClass.getInterfaces();
        // 获取权限为public的构造方法
        Constructor<?>[] constructors = reflectClass.getConstructors();
        // 获取权限为public的指定构造方法
        try {
            Constructor<ReflectDemo> constructor = reflectClass.getConstructor(Integer.class);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        // 获取所有的构造方法,按声明顺序返回.备注:先声明的下标大,后声明的下标小
        Constructor<?>[] declaredConstructors = reflectClass.getDeclaredConstructors();
        // 获取指定的构造方法
        try {
            Constructor<ReflectDemo> declaredConstructor = reflectClass.getDeclaredConstructor
                    (Integer.class);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        ///////////////////////////////////////////////////////////////////////////
        // 构造方法的常用方法
        ///////////////////////////////////////////////////////////////////////////
        // 查看该构造方法是否允许带有可变数量的参数,如果允许返回true,否则返回false
        boolean varArgs = declaredConstructors[0].isVarArgs();
        // 按照声明顺序以Class数组的形式获得该构造方法的各个参数的类型
        Class<?>[] parameterTypes = declaredConstructors[0].getParameterTypes();
        // 以Class数组的形式获得该构造方法可能抛出的异常类型
        Class<?>[] exceptionTypes = declaredConstructors[0].getExceptionTypes();
        // 通过该构造方法利用指定参数创建一个该类的对象,如果未设置参数则表示采用默认无参数的构造方法
        try {
            Object newInstance = declaredConstructors[0].newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        // 如果该构造方法的权限为private,默认为不允许通过反射利用newInstance()方法创建对象.如果先执行该方法并将参数设置为true则允许创建.
        declaredConstructors[0].setAccessible(true);
        // 获得可以解析出该构造方法所采用修饰符的整数
        int modifiers = declaredConstructors[0].getModifiers();
        boolean aPrivate = Modifier.isPrivate(modifiers);
        boolean aPublic = Modifier.isPublic(modifiers);
        boolean aProtected = Modifier.isProtected(modifiers);
        boolean aStatic = Modifier.isStatic(modifiers);
        boolean aFinal = Modifier.isFinal(modifiers);
        // 以字符串的形式返回所有的修饰符
        String s = Modifier.toString(modifiers);
        ///////////////////////////////////////////////////////////////////////////
        // 构造方法的常用方法
        ///////////////////////////////////////////////////////////////////////////

        // 获取权限为public的方法,包含从父类继承的方法
        Method[] methods = reflectClass.getMethods();
        // 获取权限为public的指定方法
        try {
            Method method = reflectClass.getMethod("clear", Integer.class);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        // 获取所有的方法,按声明顺序返回,只获得本类声明的方法
        Method[] declaredMethods = reflectClass.getDeclaredMethods();
        // 获取指定的方法
        try {
            Method clear = reflectClass.getDeclaredMethod("clear", Integer.class);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        ///////////////////////////////////////////////////////////////////////////
        // Method的常用方法
        ///////////////////////////////////////////////////////////////////////////
        // 获得方法的名称
        String name_methord = methods[0].getName();
        // 按照声明顺序以Class数组的形式获得该方法的各个参数的类型
        Class<?>[] parameterTypes_methord = methods[0].getParameterTypes();
        // 以Class对象的形式获得该方法的返回值的类型
        Class<?> returnType = methods[0].getReturnType();
        // 以Class数组的形式获得该方法可能抛出的异常类型
        Class<?>[] exceptionTypes_methord = methods[0].getExceptionTypes();
        // 利用指定对象,指定参数执行该方法
        try {
            Object returnValue = methods[0].invoke(reflectDemo, 1);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        // 查看该方法是否允许带有可变数量的参数,如果允许返回true,否则返回false
        boolean varArgs_methord = declaredConstructors[0].isVarArgs();
        // 获得可以解析出该方法所采用修饰符的整数
        int modifiers_methord = declaredConstructors[0].getModifiers();
        /**
         * 如果在定义注解时,将注解的有效范围设置为@Retention(RetentionPolicy.RUNTIME),那么在运行程序时通过反射就可以获得到相关的注解信息
         * Constructor、Method、Field均可调用以下3个关于注解的方法:
         * boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)是否添加了指定类型的注解,
         * 如果是则返回true,否则返回false
         * <T extends Annotation> T getAnnotation(Class<T> annotationClass)获得指定类型的注解,
         * 如果存在则返回相应的对象,否则返回null
         * Annotation[] getAnnotations()获得所有的注解,该方法返回一个注解的数组
         *
         * Constructor、Method中定义了Annotation[][] getParameterAnnotations()获得所有参数添加的注解,以注解类型的二维数组返回,
         * 在数组中的顺序与声明顺序相同,如果没有注解则返回一个长度为0的数组,如果存在未添加注解的参数该方法将用一个长度为0的嵌套数组占位
         * 注解对象通过 .变量名 获取变量值
         */
        if (methods[0].isAnnotationPresent(TestAnnotation.class)) {
            TestAnnotation annotation = methods[0].getAnnotation(TestAnnotation.class);
            // 获取注解的属性值
            String value = annotation.value();
            int count = annotation.count();
            char chars = annotation.chars();
        }

        ///////////////////////////////////////////////////////////////////////////
        // Method的常用方法
        ///////////////////////////////////////////////////////////////////////////
        // 获取权限为public的成员变量,包含从父类继承的成员变量
        Field[] fields = reflectClass.getFields();
        // 获取权限为public的指定变量
        try {
            Field age = reflectClass.getField("age");
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        // 获取所有的成员变量,按声明顺序返回,只获得本类声明的成员变量
        Field[] declaredFields = reflectClass.getDeclaredFields();
        // 获取指定的成员变量
        try {
            Field age = reflectClass.getDeclaredField("age");
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        ///////////////////////////////////////////////////////////////////////////
        // Field的常用方法
        ///////////////////////////////////////////////////////////////////////////
        // 获得该成员变量的名称
        String fieldName = fields[0].getName();
        // 获得该成员变量类型的Class对象
        Class<?> type = fields[0].getType();
        // 获得指定对象该成员变量的值,返回值为Object型
        try {
            Object value = fields[0].get(reflectDemo);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        // 设置指定对象该成员变量的值
        try {
            fields[0].set(reflectDemo, 1);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        // 忽略访问权限直接访问
        fields[0].setAccessible(true);
        // 获得可以解析出该构造方法所采用修饰符的整数
        int modifiers_fields = fields[0].getModifiers();
        ///////////////////////////////////////////////////////////////////////////
        // Field的常用方法
        ///////////////////////////////////////////////////////////////////////////


        // 获取权限为public的内部类
        Class<?>[] classes = reflectClass.getClasses();
        // 获取所有的内部类
        Class<?>[] declaredClasses = reflectClass.getDeclaredClasses();
        // 如果该类是内部类,则返回他的外部类,否则返回null
        Class<?> declaringClass = reflectClass.getDeclaringClass();

    }

}
